package com.idempotent.starter.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.idempotent.starter.aop.FormIdempotentAdvice;
import com.idempotent.starter.aop.IdempotentAdvice;
import com.idempotent.starter.controller.IndexController;
import com.idempotent.starter.enums.TokenType;
import com.idempotent.starter.properties.IdempotentProperties;
import com.idempotent.starter.token.TokenService;
import com.idempotent.starter.token.impl.TokenInGuavaCache;
import com.idempotent.starter.token.impl.TokenInMemery;
import com.idempotent.starter.token.impl.TokenInRedis;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.util.Objects;

/**
 * 描述：配置类
 *
 * @author huangjian
 */
@Import({IndexController.class, FormIdempotentAdvice.class, IdempotentAdvice.class})
@Slf4j
@Configuration
@EnableConfigurationProperties(IdempotentProperties.class)
public class IdempotentStaterConfig  implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    private static final ObjectMapper mapper = new ObjectMapper();

    private final IdempotentProperties idempotentProperties;

    public IdempotentStaterConfig(IdempotentProperties idempotentProperties)  {
        try {
            if(Objects.isNull(idempotentProperties)){
                throw new RuntimeException("请在上下文配置文件中配置'idempotent'相关参数");
            }else{
                if(StringUtils.isNotEmpty(idempotentProperties.getTokenType())){
                    TokenType tokenType = TokenType.valueOf(idempotentProperties.getTokenType());
                    if (Objects.isNull(tokenType)) {
                        throw new IllegalArgumentException("上下文配置文件中'idempotent.token-type'参数配置出错，请检查");
                    }
                }else{
                    log.warn("上下文配置文件中'idempotent.token-type'参数为空，启用默认策略："+TokenType.GUAVA_CACHE.name());
                }
                if(StringUtils.isEmpty(idempotentProperties.getBasePackage())){
                    throw new RuntimeException("请在上下文配置文件中配置'idempotent.base-package'相关参数");
                }
            }

            log.info("上下文配置：{}",mapper.writeValueAsString(idempotentProperties));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        this.idempotentProperties = idempotentProperties;
    }

    @Bean
    public TokenService tokenInGuavaCache() {
        return new TokenInGuavaCache();
    }

    @Bean
    public TokenService tokenInMemery() {
        return new TokenInMemery();
    }

    @Bean
    public TokenService tokenInRedis() {
        return new TokenInRedis();
    }


    @Bean(name = "tokenManager")
    public TokenService tokenService(TokenService tokenInGuavaCache,
                                     TokenService tokenInMemery,
                                     TokenService tokenInRedis) {
        TokenType tokenType = TokenType.GUAVA_CACHE;
        if(StringUtils.isNotEmpty(idempotentProperties.getTokenType())){
            tokenType = TokenType.valueOf(idempotentProperties.getTokenType());
        }
        TokenService tokenService;
        switch (tokenType) {
            case REDIS:
                tokenService = tokenInRedis;
                break;
            case MEMERY:
                tokenService = tokenInMemery;
                break;
            default:
                tokenService = tokenInGuavaCache;
        }
        return tokenService;
    }

    @Bean
    public AspectJExpressionPointcutAdvisor formIdempotentAvisor(FormIdempotentAdvice formIdempotentAdvice) {
        AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
        advisor.setExpression(idempotentProperties.getBasePackage());
        advisor.setAdvice(formIdempotentAdvice);
        return advisor;
    }

    @Bean
    public AspectJExpressionPointcutAdvisor idempotentAvisor(IdempotentAdvice idempotentAdvice) {
        AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
        advisor.setExpression(idempotentProperties.getBasePackage());
        advisor.setAdvice(idempotentAdvice);
        return advisor;
    }

    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        if(StringUtils.isEmpty(idempotentProperties.getBasePackage())){
            throw new RuntimeException("请配置basePackage参数");
        }
    }
}